package com.jbp.aspect;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.jbp.exception.RRException;
import com.jbp.model.User;
import com.jbp.redis.RedisConfigService;
import com.jbp.service.PropertyService;
import com.jbp.service.UserService;
import com.jbp.utils.Constant;
import com.jbp.utils.PropertyCacheUtil;
import com.jbp.utils.encryptUtils.AesEncryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;


/**
 * 对响应体进行加密
 */
@Component
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice {

    private static final Logger logger = LoggerFactory.getLogger(EncryptResponseBodyAdvice.class);

    @Autowired
    Gson gson;

    @Autowired
    private PropertyService propertyService;

    @Autowired
    private RedisConfigService redisConfigService;

    @Autowired
    private UserService userService;

    private HttpServletRequest request;

    /**
     * 此处如果返回false , 则不执行当前Advice的业务
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        this.request = (HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        boolean encryptBody = false;

        String encrypt = request.getHeader("encrypt");
        String debug = PropertyCacheUtil.getCachedProperty(propertyService, redisConfigService,
                "debug");
        if (!"false".equals(debug) && !"1".equalsIgnoreCase(encrypt)) {
            return  false;
        }
        return true;
    }

    /**
     * 处理响应的具体业务方法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 这里的body是一个R类的对象
        // 1. 把R类转为json字符串
        String jsonValue = gson.toJson(body);

        String uri = this.request.getRequestURI();
        // 2. 对json字符串进行加密
        if ("/login".equals(uri)) {
            // 登录接口，如果有用户信息，就使用aes加密返回；如果没有用户信息，就原样返回。

            // 如果登录成功，登录接口的返回，也要加密；如果登录失败，就不加密返回
            // 如何判断登录是否成功：code存在且为200 and data->id存在；根据id找到aes的密钥信息

            JsonElement element = gson.fromJson(jsonValue, JsonElement.class);
            JsonObject jsonObj = element.getAsJsonObject();
            try {
                JsonObject dataObj = jsonObj.get("data").getAsJsonObject();
                String userId = dataObj.get("id").getAsString();
                User user = userService.getOne(new QueryWrapper<User>().eq("id", userId));
                if (user != null) {
                    HashMap<String, String> responseBody = encryptResponse(jsonValue, response, user);
                    return responseBody;
                }
            } catch (Exception e) {
                response.getHeaders().add("usagetype", "0");
                return body;
            }

            response.getHeaders().add("usagetype", "0");
            return body;
        } else {
            // 从request中获取userid，如果获取不到，则认为用户是没有登录，直接返回body
            HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
            Object userId = servletRequest.getAttribute(Constant.USER_ID);
            if (userId == null) {
                // 鉴权失败，需要返回不加密的数据
                response.getHeaders().add("usagetype", "0");
                return body;
            } else {
                // 获取用户加密参数
                User user = userService.getOne(new QueryWrapper<User>().eq("id", userId));
                HashMap<String, String> responseBody = encryptResponse(jsonValue, response, user);
                return responseBody;
            }
        }

    }

    private HashMap<String, String> encryptResponse(String jsonValue, ServerHttpResponse response, User user) {
        String aesVipara = user.getAesVipara();
        String aesKey = user.getAesKey();
        long beforeEncrypt = System.currentTimeMillis();
        String encryptedData = AesEncryptUtil.encrypt(jsonValue, aesVipara, aesKey);
        long afterEncrypt = System.currentTimeMillis();
        //logger.info(String.format("encrypt costs: %s", (afterEncrypt-beforeEncrypt)));

        // 将加密后的数据格式，重新封装
        HashMap<String, String> responseBody = new HashMap<>();
        responseBody.put("data", encryptedData);
        response.getHeaders().add("usagetype", "1");
        return responseBody;
    }
}
